package com.wmh.baseservice.system.tools.timer.util;

import com.wmh.baseservice.common.utils.LogUtil;
import com.wmh.baseservice.common.utils.SpringContextUtil;
import com.wmh.baseservice.system.tools.timer.pojo.ScheduleJobEntity;
import org.quartz.*;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class QuartzUtil {
    public static List<String> jobNames = new ArrayList<>();

    public static String getScheduleJobName(String jobName) {
        if (jobNames.contains(jobName)) {
            return jobName;
        }
        return null;
    }

    /**
     * 创建一个定时任务，并做安排(用于继承job类的执行方法)
     * @param scheduler
     * @param scheduleJob
     * @param paramsMap
     * @param jobClass
     * @throws RuntimeException
     */
    public static CronTrigger createSheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, Map<String, Object> paramsMap, Class<? extends Job> jobClass) throws RuntimeException {
        try {
            LogUtil.info("----- scheduling job --------");
            
            // 创建一项作业
            JobDetail jobDetail = JobBuilder.newJob(jobClass)
                    .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                    .build();

            // 设置参数
            for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
                jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue());
            }

            // 作业的执行时间(当前时间的下一分钟)
//            Date runTime = DateBuilder.evenMinuteDate(new Date());

            // 创建一个触发器
            CronTrigger trigger = null;
            if (null != scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间
                        .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间
                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间
                        .build();
            } else if (null != scheduleJob.getStartDate() && null == scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间
                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间
                        .build();
            } else if (null == scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间
                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间
                        .build();
            } else {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .withSchedule(CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())) // 具体执行时间
                        .build();
            }

            // 告诉调度器使用该触发器来安排作业
            scheduler.scheduleJob(jobDetail, trigger);
            // 启动调度器
            scheduler.start();
            LogUtil.info("------ started scheduler -------");
//            LogUtil.info("------- shutting down ------");
//            // 关闭调度器
//            scheduler.shutdown(true);
//            LogUtil.info("------- shutdown complete -------");
            return trigger;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 创建一个定时任务，并做安排(用于自定义执行方法)
     * @param scheduler
     * @param scheduleJob
     * @param paramsMap
     * @throws RuntimeException
     */
    public static void createSheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, Map<String, Object> paramsMap) throws RuntimeException {
        try {
            // 新建一个基于Spring的管理Job类
            MethodInvokingJobDetailFactoryBean methodInvJobDetailFB = new MethodInvokingJobDetailFactoryBean();
            // 设置Job组名称
            methodInvJobDetailFB.setGroup(scheduleJob.getJobGroup());
            // 设置Job名称
            methodInvJobDetailFB.setName(scheduleJob.getJobName());
            // 设置任务类
            methodInvJobDetailFB.setTargetObject(SpringContextUtil.getApplicationContext().getBean(scheduleJob.getTargetObject()));
            // 设置任务方法
            methodInvJobDetailFB.setTargetMethod(scheduleJob.getTargetMethod());
            // 将管理Job类提交到计划管理类
            methodInvJobDetailFB.afterPropertiesSet();
            // 并发设置
            methodInvJobDetailFB.setConcurrent(scheduleJob.isConcurrent());

            JobDetail jobDetail = methodInvJobDetailFB.getObject();// 动态

            // 设置参数
            for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
                jobDetail.getJobDataMap().put(entry.getKey(), entry.getValue());
            }

            // jobName存入到队列 每隔一段时间就会扫描所以需要时检测
            if (!QuartzUtil.jobNames.contains(scheduleJob.getJobName())) {
                QuartzUtil.jobNames.add(scheduleJob.getJobName());
            }

            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
            // 按新的cronExpression表达式构建一个新的trigger
            CronTrigger trigger;
            if (null != scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间
                        .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间
                        .withSchedule(scheduleBuilder) // 具体执行时间
                        .build();
            } else if (null != scheduleJob.getStartDate() && null == scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .startAt(scheduleJob.getStartDate()) // 该触发器开始执行作业时间
                        .withSchedule(scheduleBuilder) // 具体执行时间
                        .build();
            } else if (null == scheduleJob.getStartDate() && null != scheduleJob.getEndDate()) {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .endAt(scheduleJob.getEndDate()) // 该触发器结束作业时间
                        .withSchedule(scheduleBuilder) // 具体执行时间
                        .build();
            } else {
                trigger = TriggerBuilder.newTrigger()
                        .withIdentity(scheduleJob.getJobName(), scheduleJob.getJobGroup())
                        .withSchedule(scheduleBuilder) // 具体执行时间
                        .build();
            }

            // 暂时停止 任务都安排完之后统一启动 解决耗时任务按照顺序部署后执行紊乱的问题
//            scheduler.standby();
            // 注入到管理类
            scheduler.scheduleJob(jobDetail, trigger);
            LogUtil.info(scheduleJob.getJobGroup() + "." + scheduleJob.getJobName() + "创建完毕");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 修改定时任务
     * @param scheduler
     * @param scheduleJob
     * @param triggerKey
     * @param trigger
     * @throws RuntimeException
     */
    public static void updateScheduler(Scheduler scheduler, ScheduleJobEntity scheduleJob, TriggerKey triggerKey, CronTrigger trigger) throws RuntimeException {
        try {
            if (!trigger.getCronExpression().equalsIgnoreCase(scheduleJob.getCronExpression())) {
                // 表达式调度构建器
                CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression());
                // 按新的cronExpression表达式重新构建trigger
                trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
                // 按新的trigger重新设置job执行
                scheduler.rescheduleJob(triggerKey, trigger);
                LogUtil.info(scheduleJob.getJobGroup() + "." + scheduleJob.getJobName() + " 更新完毕,目前cron表达式为:"
                        + scheduleJob.getCronExpression() + " concurrent: " + scheduleJob.isConcurrent());
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 删除定时任务
     * @param scheduler
     * @param triggerKey
     * @param trigger
     * @throws RuntimeException
     */
    public static void deleteScheduler(Scheduler scheduler, TriggerKey triggerKey, CronTrigger trigger) throws RuntimeException {
        try {

            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            scheduler.deleteJob(trigger.getJobKey());// 删除任务
            LogUtil.info(triggerKey.getGroup() + "." + triggerKey.getName() + "删除完毕");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 暂停定时任务
     * @param scheduler
     * @param trigger
     * @throws RuntimeException
     */
    public static void pauseScheduler(Scheduler scheduler, CronTrigger trigger) throws RuntimeException {
        try {
            scheduler.pauseJob(trigger.getJobKey());// 暂停任务
            LogUtil.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "暂停完毕");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 恢复定时任务
     * @param scheduler
     * @param trigger
     * @throws RuntimeException
     */
    public static void resumeScheduler(Scheduler scheduler, CronTrigger trigger) throws RuntimeException {
        try {
            scheduler.resumeJob(trigger.getJobKey());// 恢复任务
            LogUtil.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "恢复完毕");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 立即执行定时任务
     * @param scheduler
     * @param trigger
     * @throws RuntimeException
     */
    public static void triggerScheduler(Scheduler scheduler, CronTrigger trigger) throws RuntimeException {
        try {
            scheduler.triggerJob(trigger.getJobKey());// 立即执行任务
            LogUtil.info(trigger.getJobKey().getGroup() + "." + trigger.getJobKey().getName() + "立即执行完毕");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

}
